﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace Kernelx.Extensions
{
    /// <summary>
    /// 
    /// </summary>
    public static class GenericCollectionExtensions
    {

        /// <summary> 
        ///  检索<paramref name="source"/>的项中第一个满足<paramref name="where"/>的项的索引位置
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param> 
        /// <param name="where"></param>
        /// <returns></returns>
        public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> @where)
        {
            if (@where == null)
                throw new ArgumentException($"筛选器{nameof(@where)}不能为null");
            var index = -1;
            var current = source.GetEnumerator();
            while (current.MoveNext())
            {
                index++;
                if (@where(current.Current))
                    return index;
            }
            return -1;
        }


        #region 扩展自带的Distinct方法,支持lambda筛选
        /// <summary>
        /// 扩展自带的Distinct方法,支持lambda筛选
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, bool> comparer)
            where TSource : class
            => source.Distinct(new DefaultEqualityComparer<TSource>(comparer));

        class DefaultEqualityComparer<TSource> : IEqualityComparer<TSource>
            where TSource : class
        {

            private readonly Func<TSource, TSource, bool> _comparer;

            public DefaultEqualityComparer(Func<TSource, TSource, bool> comparer) => _comparer = comparer;


            public bool Equals(TSource x, TSource y) => _comparer(x, y);

            public int GetHashCode(TSource obj) => obj != null ? 1000 : obj.GetHashCode();
        }

        #endregion



        /// <summary> 
        /// 
        /// </summary>
        /// <typeparam name="TS"></typeparam>
        /// <typeparam name="TT"></typeparam> 
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="skipEmpty"> <paramref name="source"/>的空值属性是否跳过赋值操作,默认不跳过</param>
        /// <param name="ignoreProps">返回<typeparamref name="TT"/>类型中需要忽略赋值的属性集对象</param>
        /// <returns></returns>
        public static TT MapTo<TS, TT>(this TS source, TT target, bool skipEmpty = false, Func<TT, object> ignoreProps = null) where TS : class where TT : class
            => _ServiceContainer.GetMapper().MapTo(source, target, skipEmpty, ignoreProps);

         
        /// <summary>
        /// 返回满足条件的第一个项,并从集合中移除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T RemoveOut<T>(this IList<T> source, Func<T, bool> predicate)
        {
            var result = source.FirstOrDefault(predicate);
            if (result != null)
                source.Remove(result);
            return result;
        }


        /// <summary>
        /// 集合项转<see cref="string"/>类型按分隔符(separetor)拼接
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="separetor"></param>
        /// <param name="itemFormatFunc"></param>
        /// <returns></returns>
        public static string FormatStringSplicing<T>(this IEnumerable<T> collection, string separetor, Func<T, string> itemFormatFunc = null)
        {
            IEnumerable<string> items = collection as IEnumerable<string> ??
                collection.Select(n => itemFormatFunc != null ? itemFormatFunc(n) : n.ToString());
            return string.Join(separetor, items.ToArray());
        }


        /// <summary>
        /// 筛选集合中是指定类型的项
        /// </summary>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<TTarget> SafeCast<TTarget>(this IEnumerable source)
        {
            foreach (var item in source)
            {
                if (item is TTarget target)
                    yield return target;
            }
        }


    }
}
